"""
知识库注册表与元数据管理

负责：
- 维护多知识库的基本信息（路径、名称、时间、文件哈希等）
- 默认知识库沿用现有 config.data_dir / config.index_dir
- 新知识库自动在 storage/ 与 data/ 下创建隔离目录
"""

from __future__ import annotations

import json
import hashlib
from pathlib import Path
from typing import Dict, Any, Optional, List
from datetime import datetime

from ..config import config


def _now() -> str:
    return datetime.utcnow().isoformat()


def _slugify(name: str) -> str:
    s = name.strip().lower().replace(" ", "-")
    allowed = []
    for ch in s:
        if ch.isalnum() or ch in ("-", "_"):
            allowed.append(ch)
    slug = "".join(allowed)
    return slug or f"kb-{int(datetime.utcnow().timestamp())}"


class KBRegistry:
    def __init__(self) -> None:
        self.base_data_dir = Path(config.data_dir).resolve()
        self.base_index_dir = Path(config.index_dir).resolve()
        self.registry_path = self.base_index_dir / "kb_registry.json"
        self._data: Dict[str, Any] = {}
        self._ensure_base_dirs()
        self._load_or_init()

    # --- internal helpers ---
    def _ensure_base_dirs(self) -> None:
        self.base_data_dir.mkdir(parents=True, exist_ok=True)
        self.base_index_dir.mkdir(parents=True, exist_ok=True)
        if not self.registry_path.parent.exists():
            self.registry_path.parent.mkdir(parents=True, exist_ok=True)

    def _load_or_init(self) -> None:
        if self.registry_path.exists():
            try:
                self._data = json.loads(self.registry_path.read_text(encoding="utf-8"))
            except Exception:
                self._data = {}
        if not self._data.get("items"):
            # 初始化默认知识库，沿用现有路径
            self._data = {
                "items": {
                    "default": {
                        "id": "default",
                        "name": "默认知识库",
                        "data_dir": str(self.base_data_dir),
                        "index_dir": str(self.base_index_dir),
                        "created_at": _now(),
                        "updated_at": _now(),
                        "file_hashes": {},
                        "stats": {},
                    }
                }
            }
            self._flush()

    def _flush(self) -> None:
        self.registry_path.write_text(json.dumps(self._data, ensure_ascii=False, indent=2), encoding="utf-8")

    # --- CRUD ---
    def list_kb(self) -> List[Dict[str, Any]]:
        return list(self._data.get("items", {}).values())

    def get_kb(self, kb_id: str) -> Optional[Dict[str, Any]]:
        return self._data.get("items", {}).get(kb_id)

    def create_kb(self, name: str, data_dir: Optional[str] = None, index_dir: Optional[str] = None) -> Dict[str, Any]:
        kb_id = _slugify(name)
        items = self._data.setdefault("items", {})
        if kb_id in items:
            raise ValueError("知识库已存在")

        data_dir_path = Path(data_dir) if data_dir else (self.base_data_dir / kb_id)
        index_dir_path = Path(index_dir) if index_dir else (self.base_index_dir / kb_id)
        data_dir_path.mkdir(parents=True, exist_ok=True)
        index_dir_path.mkdir(parents=True, exist_ok=True)

        kb = {
            "id": kb_id,
            "name": name,
            "data_dir": str(data_dir_path),
            "index_dir": str(index_dir_path),
            "created_at": _now(),
            "updated_at": _now(),
            "file_hashes": {},
            "stats": {},
        }
        items[kb_id] = kb
        self._flush()
        return kb

    def delete_kb(self, kb_id: str, delete_files: bool = False) -> bool:
        if kb_id == "default":
            raise ValueError("默认知识库不支持删除")
        kb = self.get_kb(kb_id)
        if not kb:
            return False
        items = self._data.get("items", {})
        items.pop(kb_id, None)
        self._flush()

        # 处理删除动作
        from shutil import rmtree
        index_dir = Path(kb["index_dir"])
        if index_dir.exists():
            try:
                rmtree(index_dir)
            except Exception as e:
                print(f"删除索引目录失败: {e}")

        if delete_files:
            data_dir = Path(kb["data_dir"])
            if data_dir.exists():
                try:
                    rmtree(data_dir)
                except Exception as e:
                    print(f"删除数据目录失败: {e}")
        return True

    def update_stats(self, kb_id: str, stats: Dict[str, Any]) -> None:
        kb = self.get_kb(kb_id)
        if not kb:
            return
        kb["stats"] = stats
        kb["updated_at"] = _now()
        self._flush()

    def get_file_hashes(self, kb_id: str) -> Dict[str, str]:
        kb = self.get_kb(kb_id)
        if not kb:
            return {}
        return kb.get("file_hashes", {})

    def set_file_hashes(self, kb_id: str, hashes: Dict[str, str]) -> None:
        kb = self.get_kb(kb_id)
        if not kb:
            return
        kb["file_hashes"] = hashes
        kb["updated_at"] = _now()
        self._flush()

    # --- hash helpers ---
    @staticmethod
    def compute_file_hash(path: Path) -> str:
        md5 = hashlib.md5()
        with path.open("rb") as f:
            for chunk in iter(lambda: f.read(8192), b""):
                md5.update(chunk)
        return md5.hexdigest()


kb_registry = KBRegistry()


